from abc import ABC, abstractmethod

from fastapi import APIRouter, params, Request, Response
from fastapi.routing import APIRoute

from enum import Enum, IntEnum
from typing import (
    Any,
    Callable,
    Coroutine,
    Dict,
    List,
    Optional,
    Sequence,
    Set,
    Tuple,
    Type,
    Union,
)

from fastapi import params
from starlette.requests import Request
from starlette.responses import JSONResponse, Response
from starlette.routing import Mount as Mount  # noqa


class IGroupBaseAPIRouter(ABC):

    @abstractmethod
    async def register_group_router(self, router: APIRouter) -> None:
        '''
         模块路由统一注册
        :param router:
        :return:
        '''
        raise NotImplemented


class HookRequestRoute(APIRoute):

    @abstractmethod
    async def before_request(self, apiroute: APIRoute, request: Request) -> None:
        """如果需要修改请求信息，可直接重写此方法"""
        raise NotImplemented

    @abstractmethod
    async def after_request(self, request: Request, response: Response) -> None:
        """请求后的处理【记录请求耗时等，注意这里没办法对响应结果进行处理】"""
        raise NotImplemented

    def get_route_handler(self) -> Callable:
        original_route_handler = super().get_route_handler()

        async def custom_route_handler(request: Request) -> Response:
            response_info = None
            try:
                await self.before_request(self, request=request)
                response_info = await original_route_handler(request)

                return response_info
            finally:
                response = None
                if response_info:
                    response = Response(content=response_info.body,
                                        status_code=response_info.status_code,
                                        headers=dict(response_info.headers)
                                        )
                    print("路由中响应报文：", response_info.body)
                await self.after_request(request=request, response=response)
                pass

        return custom_route_handler


class IHookReqGroupAPIRouterBuilder(IGroupBaseAPIRouter):
    path_prefix: str = None
    tags: Optional[List[Union[str, Enum]]] = None
    router: Optional[APIRouter] = None
    dependencies: Optional[Sequence[params.Depends]] = None
    redirect_slashes: bool = True
    deprecated: Optional[bool] = None
    include_in_schema: bool = True

    def __init__(
            self,
            _path_prefix: str = '',
            _tags: Optional[List[Union[str, Enum]]] = None,
            _dependencies: Optional[Sequence[params.Depends]] = None,
            _deprecated: Optional[bool] = None,
            *args, **kwargs,
    ):
        # 路由前缀信息的定义
        # for v in attrs.values():
        #     if inspect.isfunction(v) and hasattr(v, '_endpoint'):
        #         endpoints.append(v._endpoint)

        # 获取当前类中定义所以的方法
        import inspect
        print([i for i in dir(IHookReqGroupAPIRouterBuilder) if
               inspect.isfunction(getattr(IHookReqGroupAPIRouterBuilder, i))])

        self._route_map = None
        self._path_prefix = self.path_prefix or _path_prefix
        # 路由组
        self._tags_fix = self.tags or _tags
        self._deprecated = self.deprecated or _deprecated
        # self._include_in_schema = self.include_in_schema or _include_in_schema
        self._router = self.router or APIRouter(prefix=self._path_prefix, tags=self._tags_fix,
                                                dependencies=self.dependencies or _dependencies,
                                                redirect_slashes=self.redirect_slashes ,
                                                include_in_schema=self.include_in_schema,
                                                deprecated=self._deprecated or _deprecated,

                                                *args, **kwargs)

    @abstractmethod
    async def before_request(self, request: Request, curr_apiroute: APIRoute) -> None:
        """如果需要修改请求信息，可直接重写此方法"""
        raise NotImplemented

    @abstractmethod
    async def after_request(self, request: Request, response: Response) -> None:
        """请求后的处理【记录请求耗时等，注意这里没办法对响应结果进行处理】"""
        raise NotImplemented

    def build(self) -> APIRouter:
        # 动态进行方法引用
        setattr(HookRequestRoute, 'before_request', self.before_request)
        setattr(HookRequestRoute, 'after_request', self.after_request)
        self._router.route_class = HookRequestRoute
        self.register_group_router(self._router)

        return self._router

    @classmethod
    def instance(cls, _path_prefix: str = '',
                 _tags: Optional[List[Union[str, Enum]]] = None,
                 _dependencies: Optional[Sequence[params.Depends]] = None,
                 *args, **kwargs) -> APIRouter:
        """实例化"""
        return cls(_path_prefix=_path_prefix,
                   _tags=_tags,
                   _dependencies=_dependencies,
                   *args, **kwargs
                   ).build()


class IGroupAPIRouterBuilder(IGroupBaseAPIRouter):
    path_prefix: str = None
    tags: Optional[List[Union[str, Enum]]] = None
    router: Optional[APIRouter] = None
    dependencies: Optional[Sequence[params.Depends]] = None
    redirect_slashes: bool = True
    deprecated: Optional[bool] = None
    include_in_schema: bool = True

    def __init__(
            self,
            _path_prefix: str = '',
            _tags: Optional[List[Union[str, Enum]]] = None,
            _dependencies: Optional[Sequence[params.Depends]] = None,
            _deprecated: Optional[bool] = None,
            *args, **kwargs,
    ):
        # 路由前缀信息的定义
        self._route_map = None
        self._path_prefix = self.path_prefix or _path_prefix
        # 路由组
        self._tags_fix = self.tags or _tags
        self._deprecated = self.deprecated or _deprecated
        self._router = self.router or APIRouter(prefix=self._path_prefix, tags=self._tags_fix,
                                                dependencies=self.dependencies or _dependencies,
                                                redirect_slashes=self.redirect_slashes ,
                                                include_in_schema=self.include_in_schema,
                                                deprecated=self._deprecated or _deprecated,

                                                *args, **kwargs)

    def build(self) -> APIRouter:
        # 动态进行方法引用
        self.register_group_router(self._router)
        return self._router

    @classmethod
    def instance(cls, _path_prefix: str = '',
                 _tags: Optional[List[Union[str, Enum]]] = None,
                 _dependencies: Optional[Sequence[params.Depends]] = None,
                 *args, **kwargs) -> APIRouter:
        """实例化"""
        return cls(_path_prefix=_path_prefix,
                   _tags=_tags,
                   _dependencies=_dependencies,
                   *args, **kwargs
                   ).build()
